package com.xiaouyudeguang.common.service.impl;

import com.xiaouyudeguang.common.dao.AbstractDao;
import com.xiaouyudeguang.common.event.LogEvent;
import com.xiaouyudeguang.common.exception.BusinessException;
import com.xiaouyudeguang.common.request.RequestDto;
import com.xiaouyudeguang.common.service.AbstractService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.domain.*;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Transactional(rollbackFor = Exception.class)
public class AbstractServiceImpl<Dao extends AbstractDao<T>, T> implements AbstractService<Dao, T> {

    protected Logger log = LoggerFactory.getLogger(getClass());

    @Autowired
    protected Dao baseDao;

    @Autowired
    protected ApplicationContext context;

    @Autowired
    protected HttpServletRequest request;

    @Override
    public T getById(String tenantId, String appId, String id) throws Exception {
        Optional<T> optional = baseDao.findById(Long.valueOf(id));
        return optional.orElse(null);
    }

    @Override
    public List<T> getByIds(String tenantId, String appId, Set<String> ids) throws Exception {
        return baseDao.findAllById(ids.stream().map(Long::valueOf).collect(Collectors.toSet()));
    }

    @Override
    public T save(String tenantId, String appId, RequestDto<T> requestDto) throws Exception {
        return baseDao.save(requestDto.getData());
    }

    @Override
    public Boolean saveBatch(String tenantId, String appId, List<T> dataList) throws Exception {
        baseDao.saveAll(dataList);
        return true;
    }

    @Override
    public Boolean deleteById(String tenantId, String appId, String id) throws Exception {
        baseDao.deleteById(Long.valueOf(id));
        return true;
    }

    @Override
    public Boolean deleteByIds(String tenantId, String appId, Set<String> ids) throws Exception {
        baseDao.deleteAllById(ids.stream().map(Long::valueOf).collect(Collectors.toSet()));
        return false;
    }

    @Override
    public Boolean updateById(String tenantId, String appId, RequestDto<T> requestDto) throws Exception {
        baseDao.save(requestDto.getData());
        return true;
    }

    @Override
    public Boolean updateByIds(String tenantId, String appId, RequestDto<T> requestDto) throws Exception {
        baseDao.save(requestDto.getData());
        return true;
    }

    @Override
    public Boolean updateBatch(String tenantId, String appId, List<T> dataList) throws Exception {
        baseDao.saveAll(dataList);
        return true;
    }

    @Override
    public Boolean modify(String tenantId, String appId, RequestDto<T> requestDto) throws Exception {
        baseDao.save(requestDto.getData());
        return true;
    }

    @Override
    public T getOne(String tenantId, String appId, RequestDto<T> requestDto) throws Exception {
        return baseDao.findOne(Example.of(requestDto.getData())).orElse(null);
    }

    @Override
    public List<T> list(String tenantId, String appId, RequestDto<T> requestDto) throws Exception {
        return baseDao.findAll(Example.of(requestDto.getData()));
    }

    @Override
    public PageImpl<T> page(String tenantId, String appId, RequestDto<T> requestDto) throws Exception {
        Page<T> page = baseDao.findAll(Example.of(requestDto.getData()), PageRequest.of(requestDto.getCurrent(), requestDto.getSize()));
        return new PageImpl<>(page.getContent(), Pageable.unpaged(), page.getNumberOfElements());
    }

    @Override
    public com.baomidou.mybatisplus.extension.plugins.pagination.Page<T> pageAll(String tenantId, String appId, RequestDto<T> requestDto) throws Exception {
        return new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>();
    }

    @Override
    public List<T> upload(String tenantId, String appId, List<T> dataList) throws Exception {
        if (dataList.size() > 100) {
            throw new BusinessException("单次导入不能超过100条");
        }
        for (T data : dataList) {
            save(tenantId, appId, RequestDto.getRequest(data));
        }
        return dataList;
    }

    @Override
    public List<T> export(String tenantId, String appId, RequestDto<T> requestDto) throws Exception {
        return page(tenantId, appId,  requestDto).getContent();
    }

    public void publish(String tenantId, String appId, String id, T data) {
        context.publishEvent(new LogEvent(tenantId, appId, id, data));
    }
}
